#include "stdafx.h"

#include <cstring>

#include "Socket.h"


namespace PC2
{

Socket::Socket(TypeEnum aType)
{
	if(aType == UDP)
	{
#ifdef WINDOWS
		m_Socket = ::WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0 , 0);
#else
		m_Socket = ::socket(PF_INET, SOCK_DGRAM, 0);
#endif
	}
}

Socket::~Socket()
{
#ifdef WINDOWS
	::closesocket(m_Socket);
#else
	::close(m_Socket);
#endif
}

SOCKETTYPE Socket::GetNativeHandle()
{
	return m_Socket;
}

int32_t Socket::Bind( char const* apAddr, unsigned short aPort, bool aReuse /*= true*/ )
{
	sockaddr_in lAddr;
	lAddr.sin_family = AF_INET;
	lAddr.sin_port = htons(aPort);
	lAddr.sin_addr.s_addr = inet_addr(apAddr);

	if (aReuse)
	{
#ifdef WINDOWS
		BOOL lTrue(TRUE);
		if (0 != setsockopt(m_Socket, SOL_SOCKET, SO_REUSEADDR, (char*)&lTrue, sizeof(BOOL)))			
			return GetLastError();
#else
		int lTrue = 1;
		if (0 != setsockopt(m_Socket, SOL_SOCKET, SO_REUSEADDR, (char*)&lTrue, sizeof(int)))
			return GetLastError();

#endif
	}

	if(0 == ::bind(m_Socket, (sockaddr*)&lAddr, sizeof(sockaddr_in)))
	{
		return 0;
	}
	else
		return GetLastError();
}

int32_t Socket::GetSocketError()
{
	int32_t lValue;
	int32_t lLen = 4;
	::getsockopt(m_Socket, SOL_SOCKET, SO_ERROR, (char*)&lValue, (socklen_t*)&lLen);
	return lValue;
}

int32_t Socket::SetReceiveBufferSize( int aSize )
{
	if(0 == ::setsockopt(m_Socket, SOL_SOCKET, SO_RCVBUF, (char*)&aSize, sizeof(int)))
		return 0;
	else
		return GetLastError();
}

int32_t Socket::Connect( char const* apAddr, unsigned short aPort )
{
	sockaddr_in lAddr;
	lAddr.sin_family = AF_INET;
	lAddr.sin_port = htons(aPort);
	lAddr.sin_addr.s_addr = inet_addr(apAddr);

	return ::connect(m_Socket, (sockaddr*)&lAddr, sizeof(sockaddr_in));
}

int32_t Socket::Receive( char* apBuffer, int32_t aLength, int32_t aFlags )
{
	return ::recv(m_Socket, apBuffer, aLength, aFlags);
}

int32_t Socket::ReceiveFrom( char* apBuffer, int32_t aLength, int32_t aFlags, char* apSrcAddr, unsigned short* apSrcPort )
{
	int lAddrLen = sizeof(sockaddr_in);
	sockaddr_in lAddr;
	int32_t lRet = ::recvfrom(m_Socket, apBuffer, aLength, aFlags, (sockaddr*)&lAddr, (socklen_t*)&lAddrLen);

	strcpy(apSrcAddr, inet_ntoa(lAddr.sin_addr));

	*apSrcPort = ntohs(lAddr.sin_port);

	return lRet;
}

int32_t Socket::Send( char const* apBuffer, int32_t aLength, int32_t aFlags )
{
	int32_t lRet = ::send(m_Socket, apBuffer, aLength, aFlags);
	return lRet;
}

int32_t Socket::SendTo( char const* apAddr, unsigned short aPort, char const* apBuffer, int32_t aLength, int32_t aFlags )
{
	sockaddr_in lAddr;
	lAddr.sin_family = AF_INET;
	lAddr.sin_port = htons(aPort);
	lAddr.sin_addr.s_addr = inet_addr(apAddr);

	return ::sendto(m_Socket, apBuffer, aLength, aFlags, (sockaddr*)&lAddr, sizeof(sockaddr_in));
}

int32_t Socket::SetNonBlockMode()
{
#ifdef WINDOWS
	u_long lNonBlock(1);
	int lRet = ::ioctlsocket(m_Socket, FIONBIO, &lNonBlock);
	return lRet;
#else
	int flags = fcntl(m_Socket, F_GETFL, 0);
	if(flags <0)
		return flags;
	flags = flags | O_NONBLOCK;
	flags = fcntl(m_Socket, F_SETFL, flags);
	if(flags < 0)
	{
		return flags;
	}
#endif
}

int Socket::GetLastError()
{
#ifdef WINDOWS
	return ::WSAGetLastError();
#else
	return errno;
#endif

}



}
